package cn.ztuo.bitrade.job;

import cn.ztuo.bitrade.Trade.CoinTrader;
import cn.ztuo.bitrade.Trade.CoinTraderFactory;
import cn.ztuo.bitrade.config.AfterServiceStarted;
import cn.ztuo.bitrade.constant.SysConstant;
import cn.ztuo.bitrade.entity.*;
import cn.ztuo.bitrade.runnable.RobotOrderRunnable;
import cn.ztuo.bitrade.service.ContractOrderService;
import cn.ztuo.bitrade.service.ContractPositionService;
import cn.ztuo.bitrade.service.ContractService;
import cn.ztuo.bitrade.util.ContractUtils;
import cn.ztuo.bitrade.util.ExceptionUtil;
import cn.ztuo.bitrade.util.MessageResult;
import cn.ztuo.bitrade.util.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
public class RobotJob {

    @Autowired
    private ContractPositionService positionService;
    @Autowired
    private ContractOrderService contractOrderService;
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    @Autowired
    private SimpMessagingTemplate messagingTemplate;
    @Autowired
    private CoinTraderFactory traderFactory;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ContractService contractService;
    @Autowired
    private RedisUtil redisUtil;

    private static Map<String, Integer> robotStatusMap = RobotOrderRunnable.robotStatusMap;

    /**
     * 强平
     */
    @Scheduled(fixedRate = 2000)
    public void forceThrowout() throws Exception {
        List<ContractPosition> positions = positionService.findAll();
        if(positions==null||positions.size()<=0){
            return;
        }
        try {
            positions.stream().filter(a -> (a.getHoldingBond().compareTo(BigDecimal.ZERO) > 0 && a.getContractTotalNum() > 0 && a.getMemberId().longValue() != 0 && a.getMemberId().longValue() != 1)).forEach(a -> {
                synchronized (a.getId().toString().intern()) {
                    a = positionService.getById(a.getId());
                    if (a.getHoldingBond().compareTo(BigDecimal.ZERO) <= 0 || a.getContractTotalNum() <= 0) {
                        return;
                    }

                    ContractOrder ask = RobotOrderRunnable.lastPrice.get(a.getSymbol() + "-ask");
                    ContractOrder bid = RobotOrderRunnable.lastPrice.get(a.getSymbol() + "-bid");

                    BigDecimal dealPrice = null;
                    if (ask == null || bid == null) {
                        return;
                    }
                    String key = SysConstant.CONTRACT_PRICE_CONTROL + a.getSymbol() + ":";
                    if (redisUtil.hasKey(key)) {
                        ContractPriceControl priceControl = (ContractPriceControl) redisUtil.get(key);
                        ask.setPrice(priceControl.getPrice());
                        bid.setPrice(priceControl.getPrice());
                    }
                    ContractCoin coin = ContractUtils.getBaseSymbol(a.getSymbol());
                    BigDecimal gainLossRate = null;
                    if (a.getPositionType() == ContractOrderPositionType.RISE) {
                        dealPrice = bid.getPrice();
                        gainLossRate = bid.getPrice().subtract(a.getPositionAvgPrice()).multiply(new BigDecimal(a.getContractTotalNum()).multiply(coin.getMinVolume()))
                                .divide(a.getHoldingBond(), 8, BigDecimal.ROUND_DOWN);
                    }
                    if (a.getPositionType() == ContractOrderPositionType.FALL) {
                        dealPrice = ask.getPrice();
                        gainLossRate = a.getPositionAvgPrice().subtract(ask.getPrice()).multiply(new BigDecimal(a.getContractTotalNum()).multiply(coin.getMinVolume()))
                                .divide(a.getHoldingBond(), 8, BigDecimal.ROUND_DOWN);
                    }

                    if (gainLossRate.compareTo(coin.getStopLossRate().negate()) <= 0 || gainLossRate.compareTo(coin.getStopGainRate()) >= 0) {
                        CoinTrader coinTrader = traderFactory.getTrader(a.getSymbol());
                        List<ContractOrder> needCancelOrders = contractOrderService.findNeedCancelOrders(a.getMemberId(), a.getPositionType());
                        MessageResult result = positionService.forcePosition(needCancelOrders, a, dealPrice, gainLossRate, coin);
                        if (result != null && result.getCode() == 0 && result.getData() != null) {
                            ContractOrder order = (ContractOrder) result.getData();
                            needCancelOrders.stream().filter(b -> b.getStatus() == ContractOrderStatus.TRADING).forEach(contractOrder -> {
                                if (contractOrder.getStatus() == ContractOrderStatus.TRADING) {
                                    coinTrader.cancelOrder(contractOrder);
                                }
                            });
                            needCancelOrders = needCancelOrders.stream().filter(b -> b.getStatus() == ContractOrderStatus.WAITING_TRIGGER && b.getType() == ContractOrderType.CHECK_FULL_STOP).collect(Collectors.toList());
                            //远程RPC服务URL,后缀为币种单位
                            JSONObject map = new JSONObject();
                            map.put("symbol", a.getSymbol());
                            map.put("orders", needCancelOrders);
                            String serviceName = "bitrade-contract-market";
                            String url = "http://" + serviceName + "/contract-market/cancelWaitingOrder";
                            restTemplate.postForObject(url, map, MessageResult.class);

                            //市价直接发送到 发送消息至Contract系统
                            kafkaTemplate.send("contract-order", order.getSymbol(), JSON.toJSONString(order));
                            messagingTemplate.convertAndSend("/topic/contract/position-force/" + a.getSymbol() + "/" + order.getMemberId(), a);
                            log.info("结束le ================================");
                            if (gainLossRate.compareTo(coin.getStopLossRate().negate()) <= 0) {
                                JSONObject map1 = new JSONObject();
                                map1.put("userId", a.getMemberId());
                                map1.put("type", 1);
                                String serviceName1 = "uc";
                                String url1 = "http://" + serviceName1 + "/uc/mobile/sendForceMessage";
                                String mrs = restTemplate.postForObject(url1, map1, String.class);
                                log.error("------------------短信:" + mrs);
                            }
                        }
                    }
                }
            });

        } catch (Exception e) {
            log.error("强平异常  e = {}", ExceptionUtil.getMessage(e));
            e.printStackTrace();
        }

    }


    @Scheduled(fixedRate = 30 * 1000)
    public void listenRobotStatus() throws Exception {
        if (AfterServiceStarted.isReday) {
            List<ContractCoin> coins = ContractUtils.findBaseSymbols();
            Map<String, Integer> map = RobotOrderRunnable.robotStatusMap;
//        robotStatusMap
            coins.stream().filter(coin -> coin.getRobotStatus() == 1 && (robotStatusMap.get(coin.getSymbol()) == null || robotStatusMap.get(coin.getSymbol()) == 0)).forEach(coin -> {
                map.put(coin.getSymbol(), coin.getRobotStatus());
                RobotOrderRunnable.robotStatusMap = map;
                contractService.robotAddOrder(coin.getSymbol());
            });
        }
    }
}
